"""
问题一：请求参数加密
解法：
    1、找到加密的请求参数 sign
    2、看源码中是否有 sign 的明文
    3、若没有sign明文则在 initiator（发起程序） 中找到生成 sign 的JS代码，进行JS逆向

接口参数分析
URL = https://c13.shuqireader.com/pcapi/chapter/contentfree/?bookId=8867235&chapterId=2049843&ut=1695276629&num=1&ver=1&aut=1695276648&sign=42ec06931613daef128b0df099b7e226
?bookId=8867235&chapterId=2049843&ut=1695276629&num=1&ver=1&aut=1695276648&sign=42ec06931613daef128b0df099b7e226
bookId=8867235&chapterId=2049843 这个两个bid和cid可以在“小说章节采集.py”中获取
num=1&ver=1 这两个是固定的
aut=1695276648 是固定的
ut=1695276629  是时间戳
sign=42ec06931613daef128b0df099b7e226 这个签名是动态生成的，并且是加密的

问题二：ChapterContent字段是加密的
解法：
    1、找到加密ChapterContent的JS代码，进行逆向，得到明文
"""
import requests  # 导入requests库，用于发送HTTP请求
import execjs  # 导入execjs库，用于执行JavaScript代码
from novel_chapter_collection import ChapterCrawler  # 从novel_chapter_collection模块中导入ChapterCrawler类
from parsel import Selector  # 从parsel模块中导入Selector类，用于解析HTML和XML文档

class SingleChapterCrawler:
    """
    单章爬虫类，用于爬取小说的单个章节内容。
    """

    def __init__(self, chapter_url, chapter_url_list):
        """
        初始化方法，设置初始参数。
        
        :param chapter_url: 当前章节的基础URL
        :param chapter_url_list: 所有章节的URL列表
        """
        self.chapter_url_list = chapter_url_list  # 保存所有章节的URL列表
        self.url = chapter_url  # 保存当前章节的基础URL
        self.headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36',
        }  # 设置请求头，模拟浏览器访问
        self.js_code = None  # 初始化JavaScript代码变量为None

    def get_sign(self, i, url):
        """
        获取签名并调用get_data方法。
        
        :param i: 当前章节的索引
        :param url: 当前章节的URL
        """
        resp = requests.get(url=url, headers=self.headers)  # 发送GET请求获取响应
        selector = Selector(text=resp.text)  # 使用Selector解析响应内容
        result = selector.css('.js-dataChapters::text').re('"contUrlSuffix":"(.*?)",')  # 提取contUrlSuffix的值
        self.get_data(result[i])  # 调用get_data方法处理提取到的数据

    def get_data(self, params):
        """
        根据参数获取章节内容并调用parse_data方法。
        
        :param params: 拼接在基础URL后的参数
        """
        try:
            print(self.url + params)  # 打印完整的请求URL
            resp = requests.get(url=self.url + params, headers=self.headers)  # 发送GET请求获取响应
            chapter_content = resp.json()['ChapterContent']  # 解析JSON响应，获取章节内容
            # print(chapter_content)  # 打印章节内容（注释掉）
            self.parse_data(chapter_content)  # 调用parse_data方法处理章节内容
        except Exception as e:
            print(e)  # 捕获异常并打印错误信息

    def parse_data(self, chapter_content):
        """
        解析章节内容并输出。
        
        :param chapter_content: 需要解析的章节内容
        """
        result = self.js_code.call('_decodeCont', chapter_content).replace('<br/><br/>', '').replace('<br/>', '')  # 调用JavaScript函数解码内容，并替换换行符
        print(result)  # 打印解析后的内容

    def run(self):
        """
        运行爬虫程序，加载JavaScript代码并遍历所有章节URL。
        """
        with open('decodeContent.js', 'r', encoding='utf-8') as f:
            text = f.read()  # 读取JavaScript文件内容
            self.js_code = execjs.compile(text)  # 编译JavaScript代码
            print(self.js_code)  # 打印编译后的JavaScript代码对象

        for i, url in enumerate(self.chapter_url_list):
            self.get_sign(i, url)  # 遍历所有章节URL，调用get_sign方法处理每个URL



if __name__ == '__main__':
    # 如果你想爬取你想要的书籍，你可以打开下面两行注释
    # bid = input('输入bid=')
    # url_list = ChapterCrawler(f'https://ognv.shuqi.com/chapter?bid={bid}').run()
    url_list = ChapterCrawler('https://ognv.shuqi.com/chapter?bid=8867235').run()  # 若自定义爬取书籍，请将此行注释
    url = 'https://c13.shuqireader.com/pcapi/chapter/contentfree/'
    spider = SingleChapterCrawler(url, url_list)
    spider.run()
